package edu.stanford.bmir.protege.web.server.stkosutil.visualizer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

import org.semanticweb.owlapi.model.OWLAnnotationProperty;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDatatype;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLEntityVisitor;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObjectProperty;

import edu.stanford.bmir.protege.web.client.rpc.data.EntityData;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.GWTExtUtil;
import edu.stanford.bmir.protege.web.server.frame.ClassFrameTranslator;
import edu.stanford.bmir.protege.web.server.frame.NamedIndividualFrameTranslator;
import edu.stanford.bmir.protege.web.server.logging.WebProtegeLogger;
import edu.stanford.bmir.protege.web.server.logging.WebProtegeLoggerManager;
import edu.stanford.bmir.protege.web.server.owlapi.OWLAPIProject;
import edu.stanford.bmir.protege.web.server.owlapi.RenderingManager;
import edu.stanford.bmir.protege.web.server.stkosutil.common.StkosUtilBaseServlet;
import edu.stanford.bmir.protege.web.server.stkosutil.visualizer.model.StkosUtilOwlEntitySimplePropertyValue;
import edu.stanford.bmir.protege.web.server.stkosutil.visualizer.model.StkosUtilOwlEntityTreeNode;
import edu.stanford.bmir.protege.web.shared.DataFactory;
import edu.stanford.bmir.protege.web.shared.PrimitiveType;
import edu.stanford.bmir.protege.web.shared.frame.ClassFrame;
import edu.stanford.bmir.protege.web.shared.frame.NamedIndividualFrame;
import edu.stanford.bmir.protege.web.shared.frame.PropertyAnnotationValue;
import edu.stanford.bmir.protege.web.shared.frame.PropertyValue;
import edu.stanford.bmir.protege.web.shared.frame.PropertyValueState;

public class StkosUtilOwlEntityTreeServlet extends StkosUtilBaseServlet {
	private static final long serialVersionUID = 1L;

	public static final WebProtegeLogger LOGGER = WebProtegeLoggerManager
			.get(StkosUtilOwlEntityTreeServlet.class);

	public static final ClassFrameTranslator CLASSTRANSLATOR = new ClassFrameTranslator();

	public static final NamedIndividualFrameTranslator NAMEDINDIVIDUALTRANSLATOR = new NamedIndividualFrameTranslator();

	private OWLAPIProject project;

	private List<StkosUtilOwlEntityTreeNode> owlEntities = new ArrayList<StkosUtilOwlEntityTreeNode>();

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		String json = "{\"success\":{0},\"msg\":{1},\"result\":{2}}";

		project = getProject(req.getParameter("projectId"));

		boolean success = false;
		String msg = "";
		String result = "\"\"";

		try {
			result = JSONObject.fromObject(getEntitiesTree()).toString();
			success = true;
			msg = "\"Getting project entities tree success.\"";
		} catch (Exception e) {
			msg = "\"Getting project entities tree failure. Details: "
					+ e.getMessage() + "\"";
		}

		json = GWTExtUtil.stringFormat(json, String.valueOf(success), msg,
				result);

		writeJson_utf8(json, resp);
	}

	private StkosUtilOwlEntityTreeNode getEntitiesTree() {

		StkosUtilOwlEntityTreeNode rootEntity = createTreeNode(DataFactory
				.getOWLThing());

		return rootEntity;
	}

	private StkosUtilOwlEntityTreeNode createTreeNode(OWLEntity owlEntity) {

		if (owlEntity == null) {
			return null;
		}

		final StkosUtilOwlEntityTreeNode owlEntityTreeNode = new StkosUtilOwlEntityTreeNode();

		owlEntity.accept(new OWLEntityVisitor() {

			@Override
			public void visit(OWLAnnotationProperty property) {

			}

			@Override
			public void visit(OWLDatatype datatype) {

			}

			@Override
			public void visit(OWLNamedIndividual individual) {
				RenderingManager rm = project.getRenderingManager();

				EntityData entityData = rm.getEntityData(individual);

				// base info
				owlEntityTreeNode.setIri(entityData.getName());
				owlEntityTreeNode.setDisplayName(entityData.getBrowserText());
				owlEntityTreeNode.setEntityType(PrimitiveType.NAMED_INDIVIDUAL);

				// properties

				NamedIndividualFrame frame = NAMEDINDIVIDUALTRANSLATOR
						.getFrame(individual, project.getRootOntology(),
								project);

				// annotation properties

				for (PropertyAnnotationValue annotation : frame
						.getAnnotationPropertyValues()) {
					if (PropertyValueState.ASSERTED.equals(annotation
							.getState())) {
						StkosUtilOwlEntitySimplePropertyValue entityPropertyValue = new StkosUtilOwlEntitySimplePropertyValue();
						entityPropertyValue.setName(annotation.getProperty()
								.toString());
						entityPropertyValue.setValue(annotation.getValue()
								.toString());
						owlEntityTreeNode.getPropertyValues().add(
								entityPropertyValue);
					}
				}

				// object properties

				for (PropertyValue logical : frame.getLogicalPropertyValues()) {
					if (PropertyValueState.ASSERTED.equals(logical.getState())) {
						StkosUtilOwlEntitySimplePropertyValue entityPropertyValue = new StkosUtilOwlEntitySimplePropertyValue();
						entityPropertyValue.setName(rm.getBrowserText(logical
								.getProperty()));
						entityPropertyValue.setValue(rm.getBrowserText(logical
								.getValue()));
						entityPropertyValue.setLogical(true);
						owlEntityTreeNode.getPropertyValues().add(
								entityPropertyValue);
					}
				}
			}

			@Override
			public void visit(OWLDataProperty property) {

			}

			@Override
			public void visit(OWLObjectProperty property) {

			}

			@Override
			public void visit(OWLClass cls) {
				if (project == null) {
					return;
				}

				RenderingManager rm = project.getRenderingManager();

				EntityData entityData = rm.getEntityData(cls);

				// base info
				owlEntityTreeNode.setIri(entityData.getName());
				owlEntityTreeNode.setDisplayName(entityData.getBrowserText());
				owlEntityTreeNode.setEntityType(PrimitiveType.CLASS);

				// subclasses
				Set<OWLClass> children = project.getClassHierarchyProvider()
						.getChildren(cls);
				if (children != null && children.size() > 0) {
					for (OWLClass owlClass : children) {
						StkosUtilOwlEntityTreeNode owlEntityTreeNode2 = createTreeNode(owlClass);
						if (owlEntityTreeNode2 != null) {
							owlEntityTreeNode.getChildren().add(
									owlEntityTreeNode2);
						}
					}
				}

				// individuals
				for (OWLIndividual individual : cls.getIndividuals(project
						.getRootOntology().getImportsClosure())) {
					if (individual != null && individual.isNamed()) {
						StkosUtilOwlEntityTreeNode owlEntityTreeNode2 = createTreeNode(individual
								.asOWLNamedIndividual());
						if (owlEntityTreeNode2 != null) {
							owlEntityTreeNode.getChildren().add(
									owlEntityTreeNode2);
						}
					}
				}

				ClassFrame frame = CLASSTRANSLATOR.getFrame(cls,
						project.getRootOntology(), project);

				// annotation properties

				for (PropertyAnnotationValue annotation : frame
						.getAnnotationPropertyValues()) {

					StkosUtilOwlEntitySimplePropertyValue entityPropertyValue = new StkosUtilOwlEntitySimplePropertyValue();
					entityPropertyValue.setName(annotation.getProperty()
							.toString());
					entityPropertyValue.setValue(annotation.getValue()
							.toString());

					owlEntityTreeNode.getPropertyValues().add(
							entityPropertyValue);
				}

				// object properties

				for (PropertyValue logical : frame.getLogicalPropertyValues()) {

					StkosUtilOwlEntitySimplePropertyValue entityPropertyValue = new StkosUtilOwlEntitySimplePropertyValue();
					entityPropertyValue.setName(rm.getBrowserText(logical
							.getProperty()));
					String value = logical.getValue().toString();
					if (value != null && value.length() > 0
							&& value.lastIndexOf(">") == (value.length() - 1)) {
						value = value.substring(1, value.length() - 1);
					}
					entityPropertyValue.setValue(value);
					entityPropertyValue.setLogical(true);

					owlEntityTreeNode.getPropertyValues().add(
							entityPropertyValue);
				}
			}
		});

		owlEntities.add(owlEntityTreeNode);

		return owlEntityTreeNode;
	}
}
